﻿using CPAIS.Model;
using CPAIS.Updater;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.SessionState;

namespace CPAIS.Web.AjaxHandlers
{
    public class LogLoadingHandler : AjaxHandler
    {
        public LogLoadingHandler(HttpContext context) : base(context) { }

        /// <summary>
        /// Ajax Request: 
        ///     RemoveLog
        /// Params:
        ///     logName
        /// Reponse:
        ///     'NotExisted' or 'OK'
        /// </summary>
        #region Ajax Request RemoveLog

        public void RemoveLog()
        {
            string logName = Params[Constants.LogName];
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            LogModel logModel = mlManager.GetLogModel(logName);
            if (logModel != null)
            {
                mlManager.RemoveLogModel(logName);
                WriteText("OK");
            }
            else
            {
                WriteText("NotExisted");
            }
        }

        #endregion

        /// <summary>
        /// Ajax Request: 
        ///     LoadLog
        /// Params:
        ///     logName
        /// Reponse:
        ///     'Started' or 'Existed'
        /// </summary>
        #region Ajax Request LoadLog

        public void LoadLog()
        {
            string logName = Params[Constants.LogName];
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            LogModel logModel = mlManager.GetLogModel(logName);
            if (logModel != null)
            {
                WriteText("Existed");
            }
            else
            {
                LoadLogUpdater updater = new LoadLogUpdater(Session, logName);
                Session.Add(Constants.LoadLogUpdater, updater);
                ThreadPool.QueueUserWorkItem(LoadingLogProc, updater);
                WriteText("Started");
            }
        }

        private class LoadLogUpdater : StateUpdater
        {
            private HttpSessionState session;
            private string logName;

            public HttpSessionState Session { get { return session; } }
            public string LogName { get { return logName; } }

            public LoadLogUpdater(HttpSessionState session, string logName)
            {
                this.session = session;
                this.logName = logName;                
            }

            protected override bool OnUpdateMessage(string message)
            {
                return session[Constants.LoadLogUpdater] != null;
            }
        }

        private void LoadingLogProc(object state)
        {
            LoadLogUpdater updater = state as LoadLogUpdater;
            DSManager dsManager = Application[Constants.DSManager] as DSManager;
            LogModel logModel = dsManager.LoadLogModel(updater.LogName, updater);
            if (updater.State == UpdateState.Completed)
            { 
                MLManager mlManager = updater.Session[Constants.MLManager] as MLManager;
                mlManager.AddLogModel(logModel);
            }
        }

        #endregion

        /// <summary>
        /// Ajax Request: 
        ///     CancelLoadLog
        /// Params:
        ///     logName
        /// Reponse:
        ///     None
        /// </summary>
        #region Ajax Request CancelLoadLog

        public void CancelLoadLog()
        {
            Session.Remove(Constants.LoadLogUpdater);
        }

        #endregion

        /// <summary>
        /// Ajax Request: 
        ///     RemoveLog
        /// Params:
        ///     logName
        /// Reponse:
        ///     QueryLoadLogProgressPackage
        /// </summary>
        #region Ajax Request QueryLoadLogProgress

        public void QueryLoadLogProgress()
        {
            LoadLogUpdater updater = Session[Constants.LoadLogUpdater] as LoadLogUpdater;
            if (updater != null)
            {
                QueryLoadLogProgressPackage package = new QueryLoadLogProgressPackage
                {
                    state = updater.State.ToString(),
                    msg = updater.Message
                };
                switch (updater.State)
                {
                    case UpdateState.Failed:
                    case UpdateState.Completed:
                        Session.Remove(Constants.LoadLogUpdater);
                        break;
                }
                WriteJson(package);
            }
        }

        private class QueryLoadLogProgressPackage
        {
            public string state { get; set; }
            public string msg { get; set; }
        }

        #endregion

        /// <summary>
        /// Ajax Request: 
        ///     GetLogSummary
        /// Params:
        ///     logName
        /// Reponse:
        ///     LogSummaryPackage
        /// </summary>
        #region Ajax Request GetLogSummary

        public void GetLogSummary()
        {
            string logName = Params[Constants.LogName];
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            LogModel logModel = mlManager.GetLogModel(logName);
            LogSummaryPackage package = new LogSummaryPackage();
            if (logModel == null)
            {
                package.state = false;
                package.data = null;
            }
            else
            {
                package.state = true;
                package.data = new object[]
                {
                    new object[]{"Log Name", logModel.LogName},
                    new object[]{"Traces", logModel.TraceCount},
                    new object[]{"Actions", logModel.TotalActions},
                    new object[]{"Average Actions", logModel.AverageActionLength.ToString("0.##")},
                    new object[]{"Maximum LOS", logModel.MaxLOS},
                    new object[]{"Minimum LOS", logModel.MinLOS},
                    new object[]{"Average LOS", logModel.AverageLOS.ToString("0.##")},
                    new object[]{"Action Types", logModel.ActionTypeCount},
                    new object[]{"Observation Types", logModel.ObservationTypeCount}, 
                    new object[]{"Diagnosis Types", logModel.DiagnosisTypeCount}
                };
            }
            WriteJson(package);
        }

        private class LogSummaryPackage
        {
            public bool state { get; set; }
            public object[] data { get; set; }
        }

        #endregion

        /// <summary>
        /// Ajax Request: 
        ///     GetTraceData
        /// Params:
        ///     logName
        /// Reponse:
        ///     TraceDataPackage
        /// </summary>
        #region Ajax Request GetTraceData

        public void GetTraceData()
        {
            string logName = Params[Constants.LogName];
            int start = int.Parse(Params[Constants.Start]);
            int limit = int.Parse(Params[Constants.Limit]);
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            LogModel logModel = mlManager.GetLogModel(logName);
            if (logModel != null)
            {
                List<TraceData> traceData = new List<TraceData>();
                foreach (var trace in logModel.Traces)
                {
                    TraceData data = new TraceData
                    {
                        pid = trace.ID,
                        sex = trace.Sex.ToString(),
                        birthday = trace.Birthday.ToString(Constants.DateFormat),
                        department = trace.Department,
                        admit = trace.Admit.ToString(Constants.DateTimeFormat),
                        discharge = trace.Discharge.ToString(Constants.DateTimeFormat),
                        cost = trace.Cost,
                        los = trace.LOS,
                        actions = trace.Actions.Count,
                        obervs = trace.Observations.Count,
                        diagnoses = trace.DiagnosisLength
                    };
                    traceData.Add(data);
                }

                TraceDataPackage package = new TraceDataPackage();
                int count = traceData.Count;
                int left = count - start;
                package.total = count;
                package.items = traceData.GetRange(start, limit <= left ? limit : left);
                WriteJson(package);
            }
        }

        private class TraceData
        {
            public string pid { get; set; }
            public string sex { get; set; }
            public string birthday { get; set; }
            public string department { get; set; }
            public string admit { get; set; }
            public string discharge { get; set; }
            public double cost { get; set; }
            public int los { get; set; }
            public int actions { get; set; }
            public int obervs { get; set; }
            public int diagnoses { get; set; }
        }

        private class TraceDataPackage
        {
            public int total { get; set; }
            public List<TraceData> items { get; set; }
        }
        
        #endregion

        /// <summary>
        /// Ajax Request: 
        ///     GetActionDetails
        /// Params:
        ///     logName
        ///     pid
        /// Reponse:
        ///     ActionData
        /// </summary>
        #region Ajax Request GetActionDetails

        public void GetActionDetails()
        {
            string logName = Params[Constants.LogName];
            string pid = Params[Constants.PID];
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            LogModel logModel = mlManager.GetLogModel(logName);
            Trace trace = logModel.GetTrace(pid);
            var actions = trace.Actions;
            var actionData = new List<ActionData>();
            foreach (var action in actions)
            {
                ActionData data = new ActionData
                {
                    timestamp = action.Timestamp.ToString(Constants.DateTimeFormat),
                    day = action.Day,
                    action = action.TypeName
                };
                actionData.Add(data);
            }
            WriteJson(actionData);
        }

        private class ActionData
        {
            public string timestamp { get; set; }
            public int day { get; set; }
            public string action { get; set; }
        }

        #endregion

        /// <summary>
        /// Ajax Request: 
        ///     GetObservationDetails
        /// Params:
        ///     logName
        ///     pid
        /// Reponse:
        ///     ObservationData
        /// </summary>
        #region Ajax Request GetObservationDetails

        public void GetObservationDetails()
        {
            string logName = Params[Constants.LogName];
            string pid = Params[Constants.PID];
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            LogModel logModel = mlManager.GetLogModel(logName);
            Trace trace = logModel.GetTrace(pid);
            var observations = trace.Observations;
            var observationData = new List<ObservationData>();
            foreach (var observ in observations)
            {
                ObservationData data = new ObservationData
                {
                    timestamp = observ.Timestamp.ToString(Constants.DateTimeFormat),
                    day = observ.Day,
                    observ = observ.TypeName
                };
                observationData.Add(data);
            }
            WriteJson(observationData);
        }

        private class ObservationData
        {
            public string timestamp { get; set; }
            public int day { get; set; }
            public string observ { get; set; }
        }

        #endregion

        /// <summary>
        /// Ajax Request: 
        ///     GetDiagnosisDetails
        /// Params:
        ///     logName
        ///     pid
        /// Reponse:
        ///     DiagnosisData
        /// </summary>
        #region Ajax Request GetDiagnosisDetails

        public void GetDiagnosisDetails()
        {
            string logName = Params[Constants.LogName];
            string pid = Params[Constants.PID];
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            LogModel logModel = mlManager.GetLogModel(logName);
            Trace trace = logModel.GetTrace(pid);
            var diagnoses = trace.Diagnoses;
            DiagnosisData[] data = new DiagnosisData[diagnoses.Length];
            for (int i = 0; i < diagnoses.Length; i++)
            {
                data[i] = new DiagnosisData { diagnosis = diagnoses[i] };
            }
            WriteJson(data);
        }

        private class DiagnosisData
        {
            public string diagnosis { get; set; }
        }

        #endregion        
    }
}